package dao

import (
	"context"
	"sale-admin/internal/dal"
	"sale-admin/internal/models"
	"strconv"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"github.com/golang-module/carbon/v2"
	"gorm.io/gorm"
)

type PaymentAmountStruct struct {
	RobotName     string  `json:"robot_name"`
	PaymentAmount float64 `json:"payment_amount"` // 实付金额
	PaidOrder     int64   `json:"paid_order"`     // 支付笔数
}
type TransactionAmountStruct struct {
	RobotName         string  `json:"robot_name"`
	TransactionAmount float64 `json:"transaction_amount"` // 交易金额
}
type DiscountAmountStruct struct {
	RobotName      string  `json:"robot_name"`
	DiscountAmount float64 `json:"discount_amount"` // 优惠金额
}
type GiveAmountStruct struct {
	RobotName  string  `json:"robot_name"`
	GiveAmount float64 `json:"give_amount"` // 赠送金额
}
type RefundStruct struct {
	RobotName         string  `json:"robot_name"`
	OutTradeNo        string  `json:"out_trade_no"`
	RefundOrderAmount float64 `json:"refund_order_amount"` // 退款金额
	RefundOrderCount  int64   `json:"refund_order_count"`  // 退款笔数
}
type OrderCreateStruct struct {
	RobotName  string `json:"robot_name"`
	OrderCount int64  `json:"order_count"` // 创单笔数
}
type OrdeNotPaidStruct struct {
	RobotName         string `json:"robot_name"`
	OrderNotPaidCount int64  `json:"order_not_paid_count"` //未支付笔数
}

type OrderDeductionStruct struct {
	DeductionLimit  float64 `json:"deduction_limit"`
	DeductionAmount float64 `json:"deduction_amount"`
	PointsAmount    float64 `json:"points_amount"`
}

type OrderOverviewStruct struct {
	RobotName         string  `json:"robot_name"`
	MerchantID        string  `json:"merchant_id"`
	SalesID           string  `json:"sales_id"`
	Areas1            string  `json:"areas1"`
	Areas2            string  `json:"areas2"`
	Areas3            string  `json:"areas3"`
	Areas5            string  `json:"areas5"`
	GMV               float64 `json:"gmv"`                  // gmv
	PaymentAmount     float64 `json:"payment_amount"`       // 实付金额
	TransactionAmount float64 `json:"transaction_amount"`   // 交易金额
	DiscountAmount    float64 `json:"discount_amount"`      // 优惠金额
	RefundAmount      float64 `json:"refund_amount"`        // 退款金额
	GiveAmount        float64 `json:"give_amount"`          // 抽奖赠送
	TotalOrder        int64   `json:"total_order"`          // 创单笔数
	TotalPaidOrder    int64   `json:"total_paid_order"`     // 支付笔数
	TotalNotPaidOrder int64   `json:"total_not_paid_order"` // 未支付笔数
	TotalRefundOrder  int64   `json:"total_refund_order"`   // 退款笔数
	TotalPaidUser     int64   `json:"total_paid_user"`      // 支付人数
}

type OrderTransactionOverviewStruct struct {
	RobotName         string  `json:"robot_name"`
	MerchantID        string  `json:"merchant_id"`
	SalesID           string  `json:"sales_id"`
	Areas1            string  `json:"areas1"`
	Areas2            string  `json:"areas2"`
	Areas3            string  `json:"areas3"`
	Areas5            string  `json:"areas5"`
	GMV               float64 `json:"gmv"`                // gmv
	PaymentAmount     float64 `json:"payment_amount"`     // 实付金额
	TransactionAmount float64 `json:"transaction_amount"` // 交易金额
	TotalPaidOrder    int64   `json:"total_paid_order"`   // 支付笔数
}

type Order struct {
	ctx   context.Context
	query *dal.Query
}

// NewOrder 初始化一个order
func NewOrder(ctx context.Context, query *dal.Query) *Order {
	return &Order{
		ctx:   ctx,
		query: query,
	}
}

// WithMerchantIDCond 商户条件
func (o *Order) WithMerchantIDCond(merchantIDs []string) *Order {
	mo := o.query.MaOrder
	if len(merchantIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.MerchantID.In(merchantIDs...)).UnderlyingDB())
	}
	return o
}

// WithDateGoodsIDCond 商品条件
func (o *Order) WithGoodsIDCond(goodsIDs []string) *Order {
	mo := o.query.MaOrder
	if len(goodsIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.GoodsID.In(goodsIDs...)).UnderlyingDB())
	}
	return o
}

// WithOutTradeNoCond 订单号条件
// 针对于end_out_trade_no 不等于 out_trade_no的情况，如支付宝刷脸附带f2,以及积分的p1。可手动去掉后缀
func (o *Order) WithOutTradeNoCond(outTradeNo string) *Order {
	mo := o.query.MaOrder
	o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.OutTradeNo.Eq(outTradeNo)).UnderlyingDB())
	return o
}

// WithChildOutTradeNoCond 子订单号条件
func (o *Order) WithChildOutTradeNoCond(childOutTradeNo string) *Order {
	mo := o.query.MaOrder
	o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.ChildOutTradeNo.Eq(childOutTradeNo)).UnderlyingDB())
	return o
}

// WithSalesIDCond 机器售卖ID条件
func (o *Order) WithSalesIDCond(salesIDs []string) *Order {
	mo := o.query.MaOrder
	if len(salesIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.SalesID.In(salesIDs...)).UnderlyingDB())
	}
	return o
}

// WithRobotName 机器id条件
func (o *Order) WithRobotIDCond(robotIDs []string) *Order {
	mo := o.query.MaOrder
	if len(robotIDs) > 0 {
		db := mo.WithContext(o.ctx).Where(mo.RobotName.In(robotIDs...)).UnderlyingDB()
		o.query = dal.Use(db)
	}
	return o
}

// WithDate 日期条件
func (o *Order) WithDateCond(date string) *Order {
	mo := o.query.MaOrder
	if date != "" {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.CreatedDate.Eq(carbon.ParseByLayout(date, carbon.DateLayout).ToStdTime())).UnderlyingDB())
	}
	return o
}

// WithTimePeriod 时间段条件
func (o *Order) WithTimePeriodCond(startTime, endTime int64) *Order {
	mo := o.query.MaOrder
	if startTime != 0 && endTime != 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.AddTime.Between(time.Unix(startTime, 0), time.Unix(endTime, 0))).UnderlyingDB())
	} else {
		startTime := carbon.Now().StartOfDay().ToStdTime()
		endTime := carbon.Now().EndOfDay().ToStdTime()
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.AddTime.Between(startTime, endTime)).UnderlyingDB())
	}
	return o
}

// WithDistrictIDCond 区县条件
func (o *Order) WithDistrictIDCond(districtIDs []string) *Order {
	mo := o.query.MaOrder
	// 将字符串数组转为int数组
	intIDs := []int{}
	for _, id := range districtIDs {
		intID, _ := strconv.Atoi(id)
		intIDs = append(intIDs, intID)
	}
	if len(intIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.Areas5.In(intIDs...)).UnderlyingDB())
	}
	return o
}

// WithLocationIDCond 位置id条件
func (o *Order) WithLocationIDCond(locationID []string) *Order {
	mo := o.query.MaOrder
	intIDs := []int{}
	for _, id := range locationID {
		intID, _ := strconv.ParseInt(id, 10, 64)
		intIDs = append(intIDs, int(intID))
	}
	if len(intIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.Areas3.In(intIDs...)).UnderlyingDB())
	}
	return o
}

// WithOrderIDCond 订单id条件
func (o *Order) WithOrderIDCond(orderIDs []string) *Order {
	mo := o.query.MaOrder
	if len(orderIDs) > 0 {
		o.query = dal.Use(mo.WithContext(o.ctx).Where(mo.OrderID.In(orderIDs...)).UnderlyingDB())
	}
	return o
}

// GroupByOutTradeNo 按订单号分组
func (o *Order) GroupByOutTradeNo() *Order {
	mo := o.query.MaOrder
	o.query = dal.Use(mo.WithContext(o.ctx).Group(mo.OutTradeNo).UnderlyingDB())
	return o
}

// OrderRobot 订单机器
func (o *Order) OrderRobot() (OrderOverview []OrderOverviewStruct, err error) {
	mo := o.query.MaOrder
	mo.WithContext(o.ctx).Session(&gorm.Session{}).
		Select(mo.RobotName, mo.MerchantID, mo.Areas1, mo.Areas2, mo.Areas3, mo.Areas5).
		Group(mo.RobotName).
		Order(mo.AddTime).
		Scan(&OrderOverview)
	return
}

// OrderDetail 订单详情
func (o *Order) OrderDetail() (res *models.MaOrder, err error) {
	mo := o.query.MaOrder
	return mo.WithContext(o.ctx).Take()
}

// List
func (o *Order) List() (res []*models.MaOrder, err error) {
	mo := o.query.MaOrder
	return mo.WithContext(o.ctx).Find()
}

// 获取机器最近的订单
func (o *Order) RobotRecentOrder(date string) OrderOverviewStruct {
	var res []struct {
		RobotName  string `json:"robot_name"`
		MerchantID string `json:"merchant_id"`
		Areas1     string `json:"areas1"`
		Areas2     string `json:"areas2"`
		Areas3     string `json:"areas3"`
		Areas5     string `json:"areas5"`
		Max        string `json:"max"`
		Min        string `json:"min"`
	}
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Select(m.RobotName, m.MerchantID, m.Areas1, m.Areas2, m.Areas3, m.Areas5,
		m.CreatedDate.Max().As("max"), m.CreatedDate.Min().As("min")).
		Group(m.RobotName, m.Areas3).
		Having(m.CreatedDate.Max().NeqCol(m.CreatedDate.Min())).
		Order(m.AddTime).
		Scan(&res)
	var maxDate string
	for k, v := range res {
		if k == 0 {
			maxDate = v.Max
		} else {
			// 上一条 max 比 当前的min小，且 相差天数大于1,处理上一条max为比当前min小一天的日期
			if carbon.Parse(maxDate).Lt(carbon.Parse(v.Min)) && carbon.Parse(maxDate).DiffInDays(carbon.Parse(v.Min)) > 1 {
				res[k-1].Max = carbon.Parse(v.Min).SubDay().ToDateString()
			}
			maxDate = v.Max
		}
	}
	for k, v := range res {
		if k == 0 && carbon.Parse(date).Lte(carbon.Parse(v.Min)) { // 比第一条小
			return OrderOverviewStruct{
				MerchantID: v.MerchantID,
				Areas1:     v.Areas1,
				Areas2:     v.Areas2,
				Areas3:     v.Areas3,
				Areas5:     v.Areas5,
			}
		} else if carbon.Parse(date).BetweenIncludedBoth(carbon.Parse(v.Min), carbon.Parse(v.Max)) { // 包含
			return OrderOverviewStruct{
				MerchantID: v.MerchantID,
				Areas1:     v.Areas1,
				Areas2:     v.Areas2,
				Areas3:     v.Areas3,
				Areas5:     v.Areas5,
			}
		} else if (k == len(res)-1) && carbon.Parse(date).Gte(carbon.Parse(v.Max)) { // 比最后一条大
			return OrderOverviewStruct{
				MerchantID: v.MerchantID,
				Areas1:     v.Areas1,
				Areas2:     v.Areas2,
				Areas3:     v.Areas3,
				Areas5:     v.Areas5,
			}
		}
	}
	return OrderOverviewStruct{}
}

// 订单概览
func (o *Order) RobotOrderOverview() (OrderOverview []OrderOverviewStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Select(m.RobotName, m.MerchantID, m.Areas1, m.Areas2, m.Areas3, m.Areas5, m.PaymentAmount.Sum().As("gmv")).
		Group(m.RobotName).
		Scan(&OrderOverview)

	if len(OrderOverview) == 0 {
		return
	}

	// 实付金额 && 支付笔数
	paymentAmount, _ := o.OrderPaymentAmountList()
	var paymentAmountMap = make(map[string]PaymentAmountStruct)
	for _, v := range paymentAmount {
		paymentAmountMap[v.RobotName] = v
	}

	// 交易金额
	transactionAmount, _ := o.OrderTransactionAmountList()
	var transactionAmountMap = make(map[string]TransactionAmountStruct)
	for _, v := range transactionAmount {
		transactionAmountMap[v.RobotName] = v
	}

	// 优惠金额
	discountAmount, _ := o.OrderDiscountAmountList()
	var discountAmountMap = make(map[string]float64)
	for _, v := range discountAmount {
		discountAmountMap[v.RobotName] = v.DiscountAmount
	}

	// 抽奖赠送
	giveAmount, _ := o.OrderGiveAmountList()
	var giveAmountMap = make(map[string]float64)
	for _, v := range giveAmount {
		giveAmountMap[v.RobotName] = v.GiveAmount
	}

	// 创单笔数
	createOrder, _ := o.OrderCreateList()
	var createOrderMap = make(map[string]int64)
	for _, v := range createOrder {
		createOrderMap[v.RobotName] = v.OrderCount
	}

	// 未支付笔数
	notPaidOrder, _ := o.OrderNotPaidList()
	var notPaidOrderMap = make(map[string]int64)
	for _, v := range notPaidOrder {
		notPaidOrderMap[v.RobotName] = v.OrderNotPaidCount
	}
	for k, v := range OrderOverview {
		if _, ok := paymentAmountMap[v.RobotName]; ok {
			OrderOverview[k].PaymentAmount = paymentAmountMap[v.RobotName].PaymentAmount
			OrderOverview[k].TotalPaidOrder = paymentAmountMap[v.RobotName].PaidOrder
		}
		if _, ok := transactionAmountMap[v.RobotName]; ok {
			OrderOverview[k].TransactionAmount = transactionAmountMap[v.RobotName].TransactionAmount
		}
		if _, ok := discountAmountMap[v.RobotName]; ok {
			OrderOverview[k].DiscountAmount = discountAmountMap[v.RobotName]
		}
		if _, ok := giveAmountMap[v.RobotName]; ok {
			OrderOverview[k].GiveAmount = giveAmountMap[v.RobotName]
		}
		if _, ok := createOrderMap[v.RobotName]; ok {
			OrderOverview[k].TotalOrder = createOrderMap[v.RobotName]
		}
		if _, ok := notPaidOrderMap[v.RobotName]; ok {
			OrderOverview[k].TotalNotPaidOrder = notPaidOrderMap[v.RobotName]
		}
	}
	return OrderOverview, nil
}

// 订单概览 -- 交易金额
func (o *Order) RobotOrderTransactionOverview() (OrderOverview []OrderTransactionOverviewStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Select(m.RobotName, m.MerchantID, m.Areas1, m.Areas2, m.Areas3, m.Areas5).
		Group(m.RobotName).
		Scan(&OrderOverview)

	if len(OrderOverview) == 0 {
		return
	}

	// 实付金额 && 支付笔数
	paymentAmount, _ := o.OrderPaymentAmountList()
	var paymentAmountMap = make(map[string]PaymentAmountStruct)
	for _, v := range paymentAmount {
		paymentAmountMap[v.RobotName] = v
	}

	// 交易金额
	transactionAmount, _ := o.OrderTransactionAmountList()
	var transactionAmountMap = make(map[string]TransactionAmountStruct)
	for _, v := range transactionAmount {
		transactionAmountMap[v.RobotName] = v
	}
	for k, v := range OrderOverview {
		if _, ok := paymentAmountMap[v.RobotName]; ok {
			OrderOverview[k].PaymentAmount = paymentAmountMap[v.RobotName].PaymentAmount
			OrderOverview[k].TotalPaidOrder = paymentAmountMap[v.RobotName].PaidOrder
		}
		if _, ok := transactionAmountMap[v.RobotName]; ok {
			OrderOverview[k].TransactionAmount = transactionAmountMap[v.RobotName].TransactionAmount
		}
	}
	return OrderOverview, nil
}

// 实付金额
func (o *Order) OrderPaymentAmountList() (result []PaymentAmountStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.OrderStatus.Eq(4)).
		Select(m.RobotName,
			m.ActualAmount.Sum().As("payment_amount"),
			m.OrderID.Count().As("paid_order"),
		).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 交易金额 = 4 出货成功 + 2 已支付 + 6 退款
func (o *Order) OrderTransactionAmountList() (result []TransactionAmountStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.OrderStatus.In(2, 4, 6)).
		Select(m.RobotName,
			m.ActualAmount.Sum().As("transaction_amount"),
		).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 优惠金额
func (o *Order) OrderDiscountAmountList() (result []DiscountAmountStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Select(m.RobotName, m.DiscountAmount.Sum().As("discount_amount")).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 赠送金额
func (o *Order) OrderGiveAmountList() (result []GiveAmountStruct, err error) {
	m := o.query.MaOrder
	//赠送订单
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.PaymentID.Eq(7), m.OrderStatus.Eq(4)).
		Select(m.RobotName, m.PaymentAmount.Sum().As("give_amount")).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 创单数
func (o *Order) OrderCreateList() (result []OrderCreateStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.OrderStatus.In([]int{1, 3, 4, 5, 6}...)).
		Select(m.RobotName,
			m.OrderID.Count().As("order_count"),
		).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 未支付数
func (o *Order) OrderNotPaidList() (result []OrdeNotPaidStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.OrderStatus.In([]int{1, 3}...)).
		Select(m.RobotName,
			m.OrderID.Count().As("order_not_paid_count"),
		).
		Group(m.RobotName).
		Scan(&result)
	return
}

// 抵扣金额
func (o *Order) OrderDeduction() (result OrderDeductionStruct, err error) {
	m := o.query.MaOrder
	tx := m.WithContext(o.ctx).Session(&gorm.Session{})
	tx.Where(m.OrderStatus.Eq(4)).
		Select(
			m.DeductionLimit.Sum().As(m.DeductionLimit.ColumnName().String()),
			m.DeductionAmount.Sum().As(m.DeductionAmount.ColumnName().String()),
			m.PointsAmount.Sum().As(m.PointsAmount.ColumnName().String()),
		).
		Scan(&result)
	return
}

// Update 更新订单
func (o *Order) Update(record models.MaOrder) error {
	mo := o.query.MaOrder
	res, _ := mo.WithContext(o.ctx).Updates(&record)
	if res.RowsAffected <= 0 {
		return errorx.New("订单更新失败", -1)
	}
	return nil
}
